package com.xaicode.learn.java.thread;

import java.util.concurrent.locks.StampedLock;

/**
 * stamped lock
 *
 * @author Locker cjxia@isoftstone.com
 * @version 1.0
 */
public class LockStamped {

    private double x, y;

    private final StampedLock sl = new StampedLock();

    void move(double deltaX, double deltaY) {
        long stamp = sl.writeLock();
        try {
            x += deltaX;
            y += deltaY;
        } finally {
            sl.unlockWrite(stamp);
        }
    }

    double distanceFromOrigin() {
        // Obtain optimistic locks
        long stamp = sl.tryOptimisticRead();
        double currentX = x, currentY = y;
        // Check if any other write locks occur when an optimistic read lock is issued
        if (!sl.validate(stamp)) {
            // If no write lock is present, a read pessimistic lock is obtained
            stamp = sl.readLock();
            try {
                currentX = x;
                currentY = y;
            } finally {
                sl.unlockRead(stamp);
            }
        }
        return Math.sqrt(currentX * currentX + currentY * currentY);
    }

    void moveIfAtOrigin(double newX, double newY) {
        long stamp = sl.readLock();
        try {
            // Check current status
            while (x == 0.0 && y == 0.0) {
                // Converts a read lock to a write lock
                long ws = sl.tryConvertToWriteLock(stamp);
                // Confirm conversion to write lock
                if (ws != 0L) {
                    // Convert write lock successfully, update ticket
                    stamp = ws;
                    x = newX;
                    y = newY;
                    break;
                } else {
                    // If the conversion is unsuccessful, release the read lock and explicitly obtain the write lock
                    sl.unlockRead(stamp);
                    stamp = sl.writeLock();
                }
            }
        } finally {
            // Release read or write locks
            sl.unlock(stamp);
        }
    }

}
